/*
 * Copyright 2004-2014 SmartBear Software
 *
 * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://ec.europa.eu/idabc/eupl
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the Licence for the specific language governing permissions and limitations
 * under the Licence.
*/
package com.eviware.soapui.impl.rest.panels.component;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.rest.RestResource;
import com.eviware.soapui.impl.rest.support.RestUtils;
import com.eviware.soapui.support.DocumentListenerAdapter;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.jgoodies.forms.factories.ButtonBarFactory;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.Document;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * Popup window displayed by the RestResourceEditor class
 */
class RestResourceEditorPopupWindow extends JDialog {

    private static final ImageIcon CONNECTOR_ICON = UISupport.createImageIcon("/connector.png");

    // package protected fields to facilitate unit testing
    JTextField basePathTextField;

    List<RestSubResourceTextField> restSubResourceTextFields;
    private RestResource targetResource;
    private RestResource focusedResource;


    RestResourceEditorPopupWindow(RestResource resource, RestResource focusedResource) {
        super(SoapUI.getFrame());
        this.targetResource = resource;
        this.focusedResource = focusedResource;
        setModal(true);
        setResizable(false);
        setMinimumSize(new Dimension(230, 0));

        JPanel contentPane = new JPanel(new BorderLayout());
        setContentPane(contentPane);


        JButton okButton = new JButton(new AbstractAction("OK") {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (basePathTextField != null) {
                    targetResource.getInterface().setBasePath(basePathTextField.getText().trim());
                }
                for (RestSubResourceTextField restSubResourceTextField : restSubResourceTextFields) {
                    restSubResourceTextField.getRestResource().setPath(restSubResourceTextField.getTextField().getText().trim());
                }
                RestResourceEditor.scanForTemplateParameters(targetResource);
                dispose();
            }
        });

        AbstractAction cancelAction = new AbstractAction("Cancel") {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        };
        JButton cancelButton = new JButton(cancelAction);
        cancelButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
        cancelButton.getActionMap().put("cancel", cancelAction);

        JPanel buttonBar = ButtonBarFactory.buildRightAlignedBar(okButton, cancelButton);
        buttonBar.setLayout(new FlowLayout(FlowLayout.RIGHT));
        contentPane.add(createResourceEditorPanel(focusedResource), BorderLayout.CENTER);
        contentPane.add(buttonBar, BorderLayout.SOUTH);
        getRootPane().setDefaultButton(okButton);

        pack();
    }

    private JPanel createResourceEditorPanel(RestResource focusedResource) {
        final JPanel panel = new JPanel(new BorderLayout());

        Box contentBox = Box.createVerticalBox();

        final JLabel changeWarningLabel = new JLabel(" ");
        changeWarningLabel.setBorder(BorderFactory.createCompoundBorder(
                contentBox.getBorder(),
                BorderFactory.createEmptyBorder(10, 0, 0, 0)));
        addBasePathFieldIfApplicable(contentBox, changeWarningLabel);
        addResourceFields(focusedResource, contentBox, changeWarningLabel);

        panel.add(contentBox, BorderLayout.NORTH);

        panel.add(changeWarningLabel, BorderLayout.CENTER);

        panel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK),
                BorderFactory.createEmptyBorder(10, 10, 10, 10)));

        return panel;
    }

    private void addResourceFields(RestResource focusedResource, Box contentBox, JLabel changeWarningLabel) {
        restSubResourceTextFields = new ArrayList<RestSubResourceTextField>();
        int rowIndex = contentBox.getComponents().length;

        for (RestResource restResource : RestUtils.extractAncestorsParentFirst(targetResource)) {
            Box row = Box.createHorizontalBox();
            row.setAlignmentX(0);
            addConnectorIfApplicable(rowIndex, row);

            final RestSubResourceTextField restSubResourceTextField = new RestSubResourceTextField(restResource);
            final JTextField innerTextField = restSubResourceTextField.getTextField();

            innerTextField.getDocument().addDocumentListener(new PathChangeListener(changeWarningLabel, restResource));
            restSubResourceTextFields.add(restSubResourceTextField);

            Box textFieldBox = createBoxWith(innerTextField);
            row.add(textFieldBox);

            contentBox.add(row);
            if (restResource == focusedResource) {
                moveFocusToField(innerTextField);
            }

            rowIndex++;
        }
    }

    private void addConnectorIfApplicable(int rowIndex, Box row) {
        if (rowIndex > 1) {
            row.add(Box.createHorizontalStrut((rowIndex - 1) * CONNECTOR_ICON.getIconWidth()));
        }
        if (rowIndex >= 1) {
            row.add(new JLabel(CONNECTOR_ICON));
        }
    }

    private void moveFocusToField(final JTextField innerTextField) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                innerTextField.requestFocusInWindow();
                innerTextField.selectAll();
            }
        });
    }

    private Box createBoxWith(JTextField innerTextField) {
        Box textFieldBox = Box.createVerticalBox();
        textFieldBox.add(Box.createVerticalGlue());
        textFieldBox.add(innerTextField);
        return textFieldBox;
    }

    class RestSubResourceTextField {
        private RestResource restResource;
        private JTextField textField;

        private RestSubResourceTextField(RestResource restResource) {
            this.restResource = restResource;
            textField = new JTextField(restResource.getPath());
            textField.setMaximumSize(new Dimension(340, (int) textField.getPreferredSize().getHeight()));
            textField.setPreferredSize(new Dimension(340, (int) textField.getPreferredSize().getHeight()));
        }

        public JTextField getTextField() {
            return textField;
        }

        public RestResource getRestResource() {
            return restResource;
        }
    }

    private void addBasePathFieldIfApplicable(Box contentBox, JLabel changeWarningLabel) {
        if (!StringUtils.isNullOrEmpty(targetResource.getInterface().getBasePath())) {
            basePathTextField = new JTextField(targetResource.getInterface().getBasePath());
            basePathTextField.getDocument().addDocumentListener(new PathChangeListener(changeWarningLabel,
                    targetResource.getTopLevelResource()));
            basePathTextField.setMaximumSize(new Dimension(340, (int) basePathTextField.getPreferredSize().getHeight()));
            Box row = Box.createHorizontalBox();
            row.setAlignmentX(0);
            row.add(createBoxWith(basePathTextField));
            contentBox.add(row);
            if (focusedResource == null) {
                moveFocusToField(basePathTextField);
            }
        }
    }

    private class PathChangeListener extends DocumentListenerAdapter {
        private final JLabel changeWarningLabel;
        private RestResource affectedRestResource;

        public PathChangeListener(JLabel changeWarningLabel, RestResource affectedRestResource) {
            this.changeWarningLabel = changeWarningLabel;
            this.affectedRestResource = affectedRestResource;
        }

        @Override
        public void update(Document document) {
            int affectedRequestCount = getRequestCountForResource(affectedRestResource);
            if (affectedRequestCount > 0) {
                changeWarningLabel.setText(String.format("<html>Changes will affect <b>%d</b> request%s</html>",
                        affectedRequestCount, affectedRequestCount > 1 ? "s" : ""));
                changeWarningLabel.setVisible(true);
            } else {
                changeWarningLabel.setVisible(false);
            }
        }

        private int getRequestCountForResource(RestResource affectedRestResource) {
            int affectedRequestCount = affectedRestResource.getRequestCount();
            for (RestResource childResource : affectedRestResource.getAllChildResources()) {
                affectedRequestCount += childResource.getRequestCount();
            }
            return affectedRequestCount;
        }
    }
}
